package com.yjb.tenet.boot.system.application.manager;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import com.yjb.tenet.boot.common.constants.GlobalConstants;
import com.yjb.tenet.boot.common.enums.CommonStatusEnum;
import com.yjb.tenet.boot.common.enums.RoleCodeEnum;
import com.yjb.tenet.boot.common.exception.CustomException;
import com.yjb.tenet.boot.common.exception.enums.ErrorCodeEnum;
import com.yjb.tenet.boot.common.utils.ServletUtils;
import com.yjb.tenet.boot.framework.satoken.core.LoginUser;
import com.yjb.tenet.boot.framework.satoken.core.utils.SecurityFrameworkUtils;
import com.yjb.tenet.boot.system.application.convert.LoginUserConvert;
import com.yjb.tenet.boot.system.application.service.SysLoginLogService;
import com.yjb.tenet.boot.system.application.service.SysUserService;
import com.yjb.tenet.boot.system.domain.entity.SysLoginLog;
import com.yjb.tenet.boot.system.domain.entity.SysRole;
import com.yjb.tenet.boot.system.domain.entity.SysUser;
import com.yjb.tenet.boot.system.infrastructure.enums.LoginLogTypeEnum;
import com.yjb.tenet.boot.system.infrastructure.enums.LoginResultEnum;
import com.xingyuv.captcha.model.common.ResponseModel;
import com.xingyuv.captcha.model.vo.CaptchaVO;
import com.xingyuv.captcha.service.CaptchaService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @description 
 * @author yinjinbiao
 * @create 2023/6/8 15:07
 * @version 1.0
 */
@Component
public class LoginManager {

	@Resource
	private SysUserService sysUserService;

	@Resource
	private SysLoginLogService sysLoginLogService;

	@Resource
	private PermissionManager permissionManager;

	@Resource
	private CaptchaService captchaService;

	public void login(String username, String password){
		SysUser sysUser = sysUserService.lambdaQuery()
				.eq(SysUser::getDeleted, GlobalConstants.NOT_DELETED)
				.eq(SysUser::getUsername, username)
				.one();
		if(ObjectUtil.isNull(sysUser)){
			throw new CustomException(ErrorCodeEnum.BUSINESS_FAIL.getCode(), "账号不存在！");
		}
		if(!sysUser.getPassword().equals(SecureUtil.md5(password))){
			createLoginLog(sysUser.getId(), sysUser.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.BAD_CREDENTIALS);
			throw new CustomException(ErrorCodeEnum.BUSINESS_FAIL.getCode(), "密码错误！");
		}
		if(sysUser.getLocked().equals(CommonStatusEnum.ENABLE.getValue())){
			createLoginLog(sysUser.getId(), sysUser.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.USER_DISABLED);
			throw new CustomException(ErrorCodeEnum.PERMISSION_DENY.getCode(), "账号已停用！");
		}
		// 登录，并缓存 token
		StpUtil.login(sysUser.getId());
		List<SysRole> roles = permissionManager.getRoles(sysUser.getId());
		Set<String> roleCodes = roles.stream().map(sysRole -> sysRole.getRoleCode()).collect(Collectors.toSet());
		Set<String> permissionCodes = permissionManager.getPermissionCodes(sysUser.getId());
		LoginUser loginUser = LoginUserConvert.INSTANCE.convert(sysUser);
		// 如果是超管多加一个通配符
		if(RoleCodeEnum.hasAnySuperAdmin(roleCodes)){
			roleCodes.add("*");
			permissionCodes.add("*");
		}
		loginUser.setRoleCodes(roleCodes);
		loginUser.setPermissionCodes(permissionCodes);

		// 获取分析数据权限
		Set<String> dataScope = permissionManager.getDataScope(roles);
		loginUser.setDataScopes(dataScope);
		Set<Long> dataScopeDeptRange = permissionManager.getDataScopeDeptRange(roles, sysUser.getDeptId());
		loginUser.setDataScopesDeptIds(dataScopeDeptRange);

		// 写入额外信息
		StpUtil.getSession().set(SecurityFrameworkUtils.LOGIN_USER_KEY, loginUser);
		createLoginLog(sysUser.getId(), username, LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.SUCCESS);
	}

	public void login(String username, String password, CaptchaVO captchaVO){
		ResponseModel response = captchaService.verification(captchaVO);
		if(response.isSuccess() == false){
			//验证码校验失败，返回信息告诉前端
			//repCode  0000  无异常，代表成功
			//repCode  9999  服务器内部异常
			//repCode  0011  参数不能为空
			//repCode  6110  验证码已失效，请重新获取
			//repCode  6111  验证失败
			//repCode  6112  获取验证码失败,请联系管理员
			createLoginLog(null, username, LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.CAPTCHA_CODE_ERROR);
			throw new CustomException(ErrorCodeEnum.PERMISSION_DENY.getCode(), response.getRepCode());
		}
		SysUser sysUser = sysUserService.lambdaQuery()
				.eq(SysUser::getDeleted, GlobalConstants.NOT_DELETED)
				.eq(SysUser::getUsername, username)
				.one();
		if(ObjectUtil.isNull(sysUser)){
			createLoginLog(sysUser.getId(), sysUser.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.BAD_CREDENTIALS);
			throw new CustomException(ErrorCodeEnum.BUSINESS_FAIL.getCode(), "账号不存在！");
		}
		if(!sysUser.getPassword().equals(SecureUtil.md5(password))){
			createLoginLog(sysUser.getId(), sysUser.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.BAD_CREDENTIALS);
			throw new CustomException(ErrorCodeEnum.BUSINESS_FAIL.getCode(), "密码错误！");
		}
		if(sysUser.getLocked().equals(CommonStatusEnum.ENABLE.getValue())){
			createLoginLog(sysUser.getId(), sysUser.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.USER_DISABLED);
			throw new CustomException(ErrorCodeEnum.PERMISSION_DENY.getCode(), "账号已停用！");
		}
		// 登录，并缓存 token
		StpUtil.login(sysUser.getId());
		List<SysRole> roles = permissionManager.getRoles(sysUser.getId());
		Set<String> roleCodes = roles.stream().map(sysRole -> sysRole.getRoleCode()).collect(Collectors.toSet());
		Set<String> permissionCodes = permissionManager.getPermissionCodes(sysUser.getId());
		LoginUser loginUser = LoginUserConvert.INSTANCE.convert(sysUser);
		// 如果是超管多加一个通配符
		if(RoleCodeEnum.hasAnySuperAdmin(roleCodes)){
			roleCodes.add("*");
			permissionCodes.add("*");
		}
		loginUser.setRoleCodes(roleCodes);
		loginUser.setPermissionCodes(permissionCodes);

		// 获取分析数据权限
		Set<String> dataScope = permissionManager.getDataScope(roles);
		loginUser.setDataScopes(dataScope);
		Set<Long> dataScopeDeptRange = permissionManager.getDataScopeDeptRange(roles, sysUser.getDeptId());
		loginUser.setDataScopesDeptIds(dataScopeDeptRange);

		// 写入额外信息
		StpUtil.getSession().set(SecurityFrameworkUtils.LOGIN_USER_KEY, loginUser);
		createLoginLog(sysUser.getId(), username, LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.SUCCESS);
	}


	/**
	 * 创建登录日志
	 * @param userId
	 * @param username
	 * @param logTypeEnum
	 * @param loginResult
	 */
	private void createLoginLog(Long userId, String username,
	                            LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) {
		// 插入登录日志
		SysLoginLog sysLoginLog = new SysLoginLog();
		sysLoginLog.setLogType(logTypeEnum.getValue());
		sysLoginLog.setUserId(userId);
		sysLoginLog.setUsername(username);
		sysLoginLog.setUserAgent(ServletUtils.getUserAgent());
		sysLoginLog.setUserIp(ServletUtils.getClientIP());
		sysLoginLog.setResult(loginResult.getValue());
		sysLoginLogService.save(sysLoginLog);
	}
}
